#pragma once

namespace rocksdb {
// The Node is a storage node used to store the kv data retrieved from the art
// tree, including a doubly linked list and kv data.
struct VersionNode {
  const char *Key() const {
    return reinterpret_cast<const char *>(version.load());
  }

  bool CASSetKey(void *expected, void *x) {
    return version.compare_exchange_strong(expected, x);
  }

  VersionNode *Next() {
    return ((&prev_next_[1])->load(std::memory_order_acquire));
  }

  VersionNode *Prev() {
    return ((&prev_next_[0])->load(std::memory_order_acquire));
  }

  void SetNext(VersionNode *x) {
    (&prev_next_[1])->store(x, std::memory_order_release);
  }

  void SetPrev(VersionNode *x) {
    (&prev_next_[0])->store(x, std::memory_order_release);
  }

  bool CASNext(VersionNode *expected, VersionNode *x) {
    return (&prev_next_[1])->compare_exchange_strong(expected, x);
  }

  bool CASPrev(VersionNode *expected, VersionNode *x) {
    return (&prev_next_[0])->compare_exchange_strong(expected, x);
  }

  // No-barrier variants that can be safely used in a few locations.
  VersionNode *NoBarrier_Next() {
    return (&prev_next_[1])->load(std::memory_order_relaxed);
  }

  void NoBarrier_SetNext(int n, VersionNode *x) {
    (&prev_next_[1])->store(x, std::memory_order_relaxed);
  }

 private:
  //  The doubly linked list associates all nodes and stores the previous
  //  node and the next node of the current node
  std::atomic<VersionNode *> prev_next_[2];
  std::atomic<void *> version;
};

}  // namespace rocksdb